home *** CD-ROM | disk | FTP | other *** search
/ The Best of Down Under Games / The Best of Down Under Games.iso / 3dfx Screen Savers / Spaghetti / main.c < prev    next >
C/C++ Source or Header  |  1997-07-12  |  27KB  |  1,033 lines

  1. // Spaghetti! Screen Saver
  2. // by Matt Lee
  3.  
  4. // This program is a real hack-job.  Only one file, lots of global variables, no
  5. // header files, etc.  I really don't know much about making a Windows C program,
  6. // so this is the result.  The final program works quite well, though.
  7.  
  8. // As for a conversion to a real MS screensaver, here's what it needs:
  9.  
  10. // * The global variables at the beginning of the file need to be stuffed with
  11. //   values from the registry at initialization.
  12. // * Some sort of UI needs to be made that will create the registry entries and
  13. //   set the appropriate values.
  14. // * The current keyboard control code needs to be deactivated.  This keyboard
  15. //   control was used during development to play around with the different
  16. //   paramaters and appearances of the spaghetti.
  17.  
  18. // The algorithm is quite simple.  The noodles are made of 90 degree pipe elbows
  19. // that rotate at the joints.  There's several types of endcaps, joints, and
  20. // centers that can be selected to further change the appearance.
  21.  
  22. // Due to the unfinished nature of the GLQuake opengl32.dll, I had to hack in
  23. // my own version of directional lighting.  It's by default coming from the +z
  24. // direction.  There is a vector to change the light's direction, but I doubt
  25. // my lighting code is robust and bug-free enough to handle other cases.
  26.  
  27. // I will most probably fix this code up at a later date; I just wanted to have
  28. // something done for the competition.
  29.  
  30. // This program only works with the old opengl32.dll (the Voodoo Graphics only
  31. // version, sized 391KB (400,896 bytes).  That DLL should be included with the
  32. // program.  I have not tested this code with Zanshin's DLL yet.
  33.  
  34. // Enjoy the program, and send all comments to mattlee@mit.edu.
  35.  
  36. #include <windows.h>
  37. #include <math.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <time.h>
  41. #include <GL/gl.h>
  42. #include <GL/glu.h>
  43. #include <GL/glaux.h>
  44.  
  45. CHAR szAppName[]="Spaghetti!";
  46. HWND  ghWnd;
  47. HDC   ghDC;
  48. HGLRC ghRC;
  49.  
  50. LONG WINAPI MainWndProc (HWND, UINT, WPARAM, LPARAM);
  51. BOOL bSetupPixelFormat(HDC);
  52. GLvoid makeTorusChunk (GLfloat major, GLfloat minor);
  53. GLvoid makecolors (int armcount, int shadestyle);
  54. GLvoid makenoodles (void);
  55. GLvoid makeSphere (void);
  56.  
  57. #define WIDTH        640
  58. #define HEIGHT       480
  59. //#define WIDTH        512
  60. //#define HEIGHT       384
  61.  
  62. #define sqr(x) ((x)*(x))
  63.  
  64. #define PI             3.14159265459f
  65. #define TEX_WIDTH    64
  66. #define TEX_HEIGHT   64
  67. #define NUM_TEXTURES 2
  68.  
  69. GLfloat PITCH_SPEED = 0.90f;
  70.  
  71. GLfloat toroid[20][20][3];
  72. GLfloat sphere[20][20][3];
  73. GLfloat snorm[20][20][3];
  74. GLfloat legcolor[20][2][3];
  75.  
  76. GLfloat rspeeds[8];
  77.  
  78. GLvoid resize(GLsizei, GLsizei);
  79. GLvoid initializeGL(GLsizei, GLsizei);
  80. GLvoid drawScene(GLvoid);
  81.  
  82. GLfloat lard = 0.3;
  83. GLfloat majrad = 1.0;
  84.  
  85. // spts - segments per toroid segment
  86. // qpr - quads per ring
  87.  
  88. int spts = 4;
  89. int qpr = 16;
  90.  
  91. int noodlecount = 3;
  92.  
  93. int armlengths [8];
  94.  
  95. int ndlmin = 5;
  96. int ndldelta = 5;
  97.  
  98. int framecount = 0;
  99.  
  100. int capstyle = 0;
  101. int centerstyle = 0;
  102. int shadestyle = 0;
  103. int bufstyle = 0;
  104.  
  105. int cycleaccum = 0;
  106. int colorcycle = 0;
  107.  
  108. float cyclepitch = 0.0;
  109. float cyclespeed = 0.05;
  110.  
  111. int jointstyle = 0;
  112.  
  113. int hackclose = 1;
  114.  
  115. struct mvect {
  116.     GLfloat x;
  117.     GLfloat y;
  118.     GLfloat z;
  119. };
  120.  
  121. typedef struct mvect vec3d;
  122.  
  123. vec3d masterlight;
  124.  
  125. /* Windows code.
  126.  *
  127.  * The windows portion of this code was taken from an MSVC example.
  128.  */
  129. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  130.            LPSTR lpCmdLine, int nCmdShow)
  131. {
  132.     MSG msg;
  133.     WNDCLASS wndclass;
  134.  
  135.     /* Register the frame class */
  136.     wndclass.style         = 0;
  137.     wndclass.lpfnWndProc   = (WNDPROC)MainWndProc;
  138.     wndclass.cbClsExtra    = 0;
  139.     wndclass.cbWndExtra    = 0;
  140.     wndclass.hInstance     = hInstance;
  141.     wndclass.hIcon         = LoadIcon (hInstance, szAppName);
  142.     wndclass.hCursor       = LoadCursor (NULL,IDC_ARROW);
  143.     wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  144.     wndclass.lpszMenuName  = szAppName;
  145.     wndclass.lpszClassName = szAppName;
  146.  
  147.     if (!RegisterClass(&wndclass))
  148.         return FALSE;
  149.  
  150.     /* Create the frame */
  151.     /* Use the WS_POPUP window style to bring up a window that is
  152.      * exactly WIDTHxHEIGHT.
  153.      */
  154.     ghWnd = CreateWindow(szAppName, "OpenGL Screensaver 1", 
  155.              WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  156.              0, 0, WIDTH, HEIGHT,
  157.              NULL, NULL, hInstance, NULL);
  158.  
  159.     /* Make sure window was created */
  160.     if (!ghWnd)
  161.         return FALSE;
  162.  
  163.     /* Show and update main window */
  164.     ShowWindow(ghWnd, nCmdShow);
  165.     UpdateWindow(ghWnd);
  166.     SetFocus (ghWnd);
  167.  
  168.     /* Animation loop */
  169.     while (hackclose) {
  170.         /* Process all pending messages */
  171.  
  172.         while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == TRUE) {
  173.             if (GetMessage(&msg, NULL, 0, 0)) {
  174.                 TranslateMessage(&msg);
  175.                 DispatchMessage(&msg);
  176.             } else {
  177.                 return TRUE;
  178.             }
  179.         }
  180.         drawScene();
  181.     }
  182. }
  183.  
  184. LONG WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  185. {
  186.     LONG lRet = 1;
  187.     PAINTSTRUCT ps;
  188.     RECT rect;
  189.  
  190.     LONG xpos = 0;
  191.     LONG ypos = 0;
  192.  
  193.     switch (uMsg) {
  194.     case WM_CREATE:
  195.         ghDC = GetDC(hWnd);
  196.         if (!bSetupPixelFormat(ghDC))
  197.             PostQuitMessage (0);
  198.  
  199.         ghRC = wglCreateContext(ghDC);
  200.         wglMakeCurrent(ghDC, ghRC);
  201.         GetClientRect(hWnd, &rect);
  202.         initializeGL(rect.right, rect.bottom);
  203.         break;
  204.  
  205.     case WM_PAINT:
  206.         BeginPaint(hWnd, &ps);
  207.         EndPaint(hWnd, &ps);
  208.         break;
  209.  
  210.     case WM_SIZE:
  211.         GetClientRect(hWnd, &rect);
  212.         resize(rect.right, rect.bottom);
  213.         break;
  214.  
  215.     case WM_CLOSE:
  216.         if (ghRC)
  217.             wglDeleteContext(ghRC);
  218.         if (ghDC)
  219.             ReleaseDC(hWnd, ghDC);
  220.         ghRC = 0;
  221.         ghDC = 0;
  222.  
  223.         DestroyWindow (hWnd);
  224.         break;
  225.  
  226.     case WM_DESTROY:
  227.         if (ghRC)
  228.             wglDeleteContext(ghRC);
  229.         if (ghDC)
  230.             ReleaseDC(hWnd, ghDC);
  231.  
  232.         PostQuitMessage (0);
  233.         break;
  234.  
  235.     case WM_MOUSEMOVE:
  236. //        hackclose = 0;
  237.         break;
  238.     
  239.     case WM_KEYDOWN:
  240. //        hackclose = 0;
  241. //        break;
  242.  
  243.         switch (wParam) {
  244.         case VK_ESCAPE:
  245.             hackclose = 0;
  246.             break;
  247.         case VK_SPACE:
  248.             makecolors (noodlecount, shadestyle);
  249.             break; 
  250.         case VK_LEFT:
  251.             if (majrad > 0.05)
  252.                 majrad -= 0.05;
  253.             makeTorusChunk (majrad, lard);
  254.             break;
  255.         case VK_RIGHT:
  256.             if (majrad < 3.0)
  257.                 majrad += 0.05;
  258.             makeTorusChunk (majrad, lard);
  259.             break; 
  260.         case VK_UP:
  261.             if (lard < 1.5)
  262.                 lard += 0.025;
  263.             makeTorusChunk (majrad, lard);
  264.             break;
  265.         case VK_DOWN:
  266.             if (lard >= 0.025)
  267.                 lard -= 0.025;
  268.             makeTorusChunk (majrad, lard);
  269.             break;
  270.         case VK_HOME:
  271.             if (spts < 16)
  272.                 spts++;
  273.             makeTorusChunk (majrad, lard);
  274.             makeSphere ();
  275.             break;
  276.         case VK_END:
  277.             if (spts > 4)
  278.                 spts--;
  279.             makeTorusChunk (majrad, lard);
  280.             makeSphere ();
  281.             break;
  282.         case VK_INSERT:
  283.             if (qpr < 16)
  284.                 qpr++;    
  285.             makeTorusChunk (majrad, lard);
  286.             makeSphere ();
  287.             break;
  288.         case VK_DELETE:
  289.             if (qpr > 3)
  290.                 qpr--;
  291.             makeTorusChunk (majrad, lard);
  292.             makeSphere ();
  293.             break; 
  294.         case VK_PRIOR:
  295.             if (PITCH_SPEED < 5.0f)
  296.                 PITCH_SPEED += 0.05f;    
  297.             break;
  298.         case VK_NEXT:
  299.             if (PITCH_SPEED > 0.0f)
  300.                 PITCH_SPEED -= 0.05f;    
  301.             break;
  302.         case VK_ADD:
  303.             if (noodlecount < 8)
  304.                 noodlecount++;
  305.             break;
  306.         case VK_SUBTRACT:
  307.             if (noodlecount > 1)
  308.                 noodlecount--;
  309.             break;
  310.         case VK_NUMPAD8:
  311.             if (ndlmin < 20)
  312.                 ndlmin++;
  313.             makenoodles (0);
  314.             break;
  315.         case VK_NUMPAD2:
  316.             if (ndlmin > 1)
  317.                 ndlmin--;
  318.             makenoodles (0);
  319.             break;
  320.         case VK_NUMPAD6:
  321.             if (ndldelta < 5)
  322.                 ndldelta++;
  323.             makenoodles (0);
  324.             break;
  325.         case VK_NUMPAD4:
  326.             if (ndldelta > 0)
  327.                 ndldelta--;
  328.             makenoodles (0);
  329.             break;
  330.         case VK_F1:
  331.             jointstyle++;
  332.             if (jointstyle > 2)
  333.                 jointstyle = 0;
  334.             break;
  335.         case VK_F2:
  336.             capstyle++;
  337.             if (capstyle > 2)
  338.                 capstyle = 0;
  339.             break;
  340.         case VK_F3:
  341.             centerstyle++;
  342.             if (centerstyle > 2)
  343.                 centerstyle = 0;
  344.             break;
  345.         case VK_F4:
  346.             shadestyle++;
  347.             if (shadestyle > 3)
  348.                 shadestyle = 0;
  349.             break;
  350.         case VK_F5:
  351.             bufstyle++;
  352.             if (bufstyle > 1)
  353.                 bufstyle = 0;
  354.             break;
  355.     default:
  356.         break;
  357.         }
  358.  
  359.     default:
  360.         lRet = DefWindowProc (hWnd, uMsg, wParam, lParam);
  361.         break;
  362.     }
  363.  
  364.     return lRet;
  365. }
  366.  
  367. BOOL bSetupPixelFormat(HDC hdc)
  368. {
  369.     PIXELFORMATDESCRIPTOR pfd, *ppfd;
  370.     int pixelformat;
  371.  
  372.     ppfd = &pfd;
  373.  
  374.     ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
  375.     ppfd->nVersion = 1;
  376.     ppfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  377.     ppfd->dwLayerMask = PFD_MAIN_PLANE;
  378.     ppfd->iPixelType = PFD_TYPE_RGBA;
  379.     ppfd->cColorBits = 16;
  380.     ppfd->cDepthBits = 16;
  381.     ppfd->cAccumBits = 0;
  382.     ppfd->cStencilBits = 0;
  383.  
  384.     pixelformat = ChoosePixelFormat(hdc, ppfd);
  385.  
  386.     if ((pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0) {
  387.         MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
  388.         return FALSE;
  389.     }
  390.  
  391.     if (pfd.dwFlags & PFD_NEED_PALETTE) {
  392.         MessageBox(NULL, "Needs palette", "Error", MB_OK);
  393.         return FALSE;
  394.     }
  395.  
  396.     if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE) {
  397.         MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
  398.         return FALSE;
  399.     }
  400.  
  401.     return TRUE;
  402. }
  403.  
  404. /* OpenGL code */
  405.  
  406. GLvoid resize( GLsizei width, GLsizei height )
  407. {
  408.     GLfloat aspect;
  409.  
  410.     glViewport(0, 0, width, height);
  411.  
  412.     aspect = (GLfloat)width/(GLfloat)height;
  413.  
  414.     glMatrixMode(GL_PROJECTION);
  415.     glLoadIdentity();
  416.     gluPerspective(45.0, aspect, 3.0, 200.0);
  417.     glMatrixMode(GL_MODELVIEW);
  418. }    
  419.  
  420. GLfloat frandom ()
  421. {
  422.     return (((GLfloat) (rand () % 100)) / 100.0f);
  423. }
  424.  
  425. GLvoid makecolors (int armcount, int style) {
  426.     int i;
  427.  
  428.     for (i = 0; i < 20; i++) {
  429.         legcolor [i][0][0] = 1.0 * frandom ();
  430.         legcolor [i][0][1] = 1.0 * frandom ();
  431.         legcolor [i][0][2] = 1.0 * frandom ();
  432.         legcolor [i][1][0] = 0.6 * frandom ();
  433.         legcolor [i][1][1] = 0.7 * frandom ();
  434.         legcolor [i][1][2] = 0.3 * frandom ();
  435.     }
  436. }
  437.  
  438. GLvoid cyclecolors (float pitch) {
  439.     int i;
  440.  
  441.     for (i = 0; i < 20; i++) {
  442.         legcolor [i][0][0] = 1.0 * sin (pitch / 10 + i + 0.010 * rspeeds [(int)pitch % 8]);
  443.         legcolor [i][0][1] = 1.0 * cos (pitch / 12 + i + 0.010 * rspeeds [((int)pitch + 1) % 8]);
  444.         legcolor [i][0][2] = 1.0 * sin (pitch / 15 + i + 0.010 * rspeeds [((int)pitch + 3) % 8]);
  445.         legcolor [i][1][0] = 0.6 * cos (pitch / 17 + i + 0.015 * rspeeds [((int)pitch + 6) % 8]);
  446.         legcolor [i][1][1] = 0.7 * sin (pitch / 14 + i + 0.013 * rspeeds [((int)pitch + 2) % 8]);
  447.         legcolor [i][1][2] = 0.3 * cos (pitch / 20 + i + 0.018 * rspeeds [((int)pitch + 4) % 8]);
  448.     }
  449. }
  450.  
  451. GLvoid makenoodles (int mode) {
  452.     int i;
  453.  
  454.     for (i = 0; i < 8; i++) {
  455.         if (mode == 1) 
  456.             rspeeds [i] = frandom () + 0.5;
  457.         if (ndldelta == 0)
  458.             armlengths [i] = ndlmin;
  459.         else
  460.             armlengths [i] = (rand () % ndldelta) + ndlmin;
  461.     }
  462. }
  463.  
  464. GLvoid initializeGL(GLsizei width, GLsizei height)
  465. {
  466.     GLfloat aspect;
  467.     int i;
  468.  
  469.     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
  470.     glClearDepth(1.0);
  471.     glDepthFunc(GL_LEQUAL);
  472.     glShadeModel(GL_SMOOTH);
  473.  
  474.     glEnable(GL_DEPTH_TEST);
  475.     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  476.  
  477.     glEnable(GL_POLYGON_SMOOTH);
  478.     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  479.     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  480.  
  481.     glMatrixMode(GL_PROJECTION);
  482.     aspect = (GLfloat)width/(GLfloat)height;
  483.     gluPerspective(45.0, aspect, 3.0, 200.0);
  484.     glMatrixMode(GL_MODELVIEW);
  485.     makeTorusChunk (majrad, lard);
  486.     makeSphere ();
  487.     srand( (unsigned)time( NULL ) );
  488.     makecolors (20, shadestyle);
  489.     makenoodles (1);
  490.     masterlight.x = 0.0;
  491.     masterlight.y = 0.0;
  492.     masterlight.z = 1.0;
  493. }
  494.  
  495. GLint random ()
  496. {
  497.     return ((rand () % 100) - 50);
  498. }
  499.  
  500. GLvoid drawTetra (GLfloat alpha) {
  501.     glBegin (GL_TRIANGLE_FAN);
  502.     glColor4f (1.0f, 0.0f, 0.0f, alpha);
  503.     glVertex3f (0.0f, 1.0f, 0.0f);
  504.     glColor4f (1.0f, 1.0f, 0.0f, alpha);
  505.     glVertex3f (0.0f, -0.732f, 1.0f);
  506.     glColor4f (0.0f, 1.0f, 0.0f, alpha);
  507.     glVertex3f (1.0f, -0.732f, -0.732f);
  508.     glColor4f (0.0f, 0.0f, 1.0f, alpha);
  509.     glVertex3f (-1.0f, -0.732f, -0.732f);
  510.     glColor4f (1.0f, 1.0f, 0.0f, alpha);
  511.     glVertex3f (0.0f, -0.732f, 1.0f);
  512.     glEnd ();
  513.     glBegin (GL_TRIANGLES);
  514.     glColor4f (1.0f, 1.0f, 0.0f, alpha);
  515.     glVertex3f (0.0f, -0.732f, 1.0f);
  516.     glColor4f (0.0f, 1.0f, 0.0f, alpha);
  517.     glVertex3f (1.0f, -0.732f, -0.732f);
  518.     glColor4f (0.0f, 0.0f, 1.0f, alpha);
  519.     glVertex3f (-1.0f, -0.732f, -0.732f);
  520.     glEnd ();
  521. }
  522.  
  523. float atan2fix (float a, float b) {
  524.     if ((a == 0.0) && (b == 0.0))
  525.         return (0.0);
  526.     else 
  527.         return (atan2 (a, b));
  528. }
  529.  
  530. vec3d vecrotate (vec3d vect, GLfloat angle, int a, int b, int c) {
  531.     vec3d t;
  532.     float theta;
  533.     float rad;
  534.     t.x = vect.x;
  535.     t.y = vect.y;
  536.     t.z = vect.z;
  537.     angle *= (PI / 180);
  538.     if (a == 1) {
  539.         t.x = vect.x;
  540.         theta = atan2fix (vect.y, vect.z);
  541.         if (theta < 0)
  542.             theta += (2 * PI);
  543.         theta += angle;
  544.         rad = sqrt (vect.y * vect.y + vect.z * vect.z);
  545.         t.y = rad * sin (theta);
  546.         t.z = rad * cos (theta);
  547.     } else if (b == 1) {
  548.         t.y = vect.y;
  549.         theta = atan2fix (-vect.z, vect.x);
  550.         if (theta < 0)
  551.             theta += (2 * PI);
  552.         theta += angle;
  553.         rad = sqrt (vect.z * vect.z + vect.x * vect.x);
  554.         t.z = rad * sin (theta);
  555.         t.x = rad * cos (theta);
  556.     } else if (c == 1) {
  557.         t.z = vect.z;
  558.         theta = atan2fix ((double)vect.y, (double)vect.x);
  559.         if (theta < 0)
  560.             theta += (2 * PI);
  561.         theta += angle;
  562.         rad = sqrt (vect.y * vect.y + vect.x * vect.x); 
  563.         t.x = rad * sin (theta);
  564.         t.y = rad * cos (theta); 
  565.     }
  566.  
  567.     return (t);
  568.  
  569. }
  570.  
  571. vec3d vmult (GLfloat scalar, vec3d vect) {
  572.     vec3d t;
  573.     t.x = vect.x * scalar;
  574.     t.y = vect.y * scalar;
  575.     t.z = vect.z * scalar;
  576.     return (t);
  577. }
  578.  
  579. vec3d vadd (vec3d a, vec3d b) {
  580.     vec3d temp;
  581.     temp.x = a.x + b.x;
  582.     temp.y = a.y + b.y;
  583.     temp.z = a.z + b.z;
  584.     return (temp);
  585. }
  586.  
  587. vec3d vclear (GLvoid) {
  588.     vec3d t;
  589.     t.x = 0.0;
  590.     t.y = 0.0;
  591.     t.z = 0.0;
  592.     return (t);
  593. }
  594.  
  595. GLvoid vset (int tsegment, int tvert, vec3d input) {
  596.     toroid [tsegment][tvert][0] = input.x;
  597.     toroid [tsegment][tvert][1] = input.y;
  598.     toroid [tsegment][tvert][2] = input.z;
  599. }
  600.  
  601. GLvoid nset (int tsegment, int tvert, vec3d input) {
  602.     snorm [tsegment][tvert][0] = input.x;
  603.     snorm [tsegment][tvert][1] = input.y;
  604.     snorm [tsegment][tvert][2] = input.z;
  605. }
  606.  
  607. GLvoid vfix (int tsegment) {
  608.     toroid [tsegment][qpr][0] = toroid [tsegment][0][0];
  609.     toroid [tsegment][qpr][1] = toroid [tsegment][0][1];
  610.     toroid [tsegment][qpr][2] = toroid [tsegment][0][2];
  611. }
  612.  
  613. GLvoid sset (int ring, int vert, vec3d input) {
  614.     sphere [ring][vert][0] = input.x;
  615.     sphere [ring][vert][1] = input.y;
  616.     sphere [ring][vert][2] = input.z;
  617. }
  618.  
  619. GLvoid makeTorusChunk (GLfloat major, GLfloat minor) {
  620.     int i, j;
  621.     GLfloat mjtheta = 0.0;
  622.     GLfloat mntheta = 0.0;
  623.     GLfloat mjdelta = ((PI * 0.5) / spts);
  624.     GLfloat mndelta = ((PI * 2) / qpr);
  625.     vec3d majorad;
  626.     vec3d minorxz;
  627.     vec3d minory;
  628.     vec3d temp;
  629.     vec3d vofs;
  630.     vec3d n;
  631.  
  632.     vofs = vclear ();
  633.     vofs.x = -major;
  634.  
  635.     minory.x = 0.0;
  636.     minory.z = 0.0;
  637.     minory.y = -1.0;
  638.     majorad.y = 0.0;
  639.     minorxz.y = 0.0;
  640.  
  641.     for (mjtheta = 0.0, i = 0; i <= spts; mjtheta += mjdelta, i++) {
  642.         majorad.x = cos (mjtheta);
  643.         majorad.z = sin (mjtheta);
  644.         minorxz.x = cos (mjtheta);
  645.         minorxz.z = sin (mjtheta);
  646.         majorad = vmult (major, majorad);
  647.         for (mntheta = 0.0, j = 0; j < qpr; mntheta += mndelta, j++) {
  648.             temp = vclear ();
  649.             temp = vadd (vmult (cos (mntheta) * minor, minory),
  650.                          vmult (sin (mntheta) * minor, minorxz));
  651.             n = vmult (1 / minor, temp);
  652.             nset (i, j, n);
  653.             temp = vadd (temp, majorad);
  654.             temp = vadd (temp, vofs);
  655.             vset (i, j, temp);
  656.         }
  657.         vfix (i);
  658.     }
  659. }
  660.  
  661. GLvoid makeSphere (void) {
  662.     GLfloat theta = 0.0;
  663.     GLfloat phi = 0.0;
  664.     GLfloat dtheta = (2.0 * PI) / (GLfloat)qpr;
  665.     GLfloat dphi = (PI / 2.0) / (GLfloat)spts;
  666.     vec3d r;
  667.     int i, j;
  668.  
  669.     for (i = 0, phi = 0.0; i <= spts; i++, phi += dphi) {
  670.         r.y = sin (phi);
  671.         for (j = 0, theta = 0.0; j < qpr; j++, theta += dtheta) {
  672.             r.x = cos (phi) * cos (theta);
  673.             r.z = cos (phi) * sin (theta);
  674.             sset (i, j, r);
  675.         }
  676.     }
  677. }
  678.  
  679. GLvoid drawAxes (void) {
  680.     glBegin (GL_TRIANGLE_FAN);
  681.     glColor3f (1.0, 0.0, 0.0);
  682.     glVertex3f (1.0, 0.0, 0.0);
  683.     glVertex3f (0.0, 0.05, 0.0);
  684.     glVertex3f (0.0, 0.0, 0.05);
  685.     glVertex3f (0.0, 0.0, 0.0);
  686.     glVertex3f (0.0, 0.05, 0.0);
  687.     glEnd ();
  688.     glBegin (GL_TRIANGLE_FAN);
  689.     glColor3f (0.0, 1.0, 0.0);
  690.     glVertex3f (0.0, 1.0, 0.0);
  691.     glVertex3f (0.05, 0.0, 0.0);
  692.     glVertex3f (0.0, 0.0, 0.05);
  693.     glVertex3f (0.0, 0.0, 0.0);
  694.     glVertex3f (0.05, 0.0, 0.0);
  695.     glEnd ();
  696.     glBegin (GL_TRIANGLE_FAN);
  697.     glColor3f (0.0, 0.0, 1.0);
  698.     glVertex3f (0.0, 0.0, 1.0);
  699.     glVertex3f (0.05, 0.0, 0.0);
  700.     glVertex3f (0.0, 0.05, 0.0);
  701.     glVertex3f (0.0, 0.0, 0.0);
  702.     glVertex3f (0.05, 0.0, 0.0);
  703.     glEnd ();
  704. }
  705.  
  706. GLvoid limbcolor (int armnum, int link, int head, GLfloat adder) {
  707.     switch (shadestyle) {
  708.         case 0:    glColor3f (legcolor [armnum][0][0] * adder, legcolor [armnum][0][1] * adder,
  709.                             legcolor [armnum][0][2] * adder);
  710.                 break;
  711.         case 1:    glColor3f (legcolor [armnum][head][0] * adder, 
  712.                             legcolor [armnum][head][1] * adder,
  713.                             legcolor [armnum][head][2] * adder);
  714.                 break;
  715.         case 2: if (rand () < 16384) head = !head;
  716.                 glColor3f (legcolor [armnum][head][0] * adder, 
  717.                             legcolor [armnum][head][1] * adder,
  718.                             legcolor [armnum][head][2] * adder);
  719.                 break;
  720.         case 3:    glColor3f (legcolor [armnum][head][0] * adder / link, 
  721.                             legcolor [armnum][head][1] * adder / link,
  722.                             legcolor [armnum][head][2] * adder / link);
  723.                 break;
  724.     }
  725. }
  726.  
  727. GLfloat surfintense (int segment, int pos, vec3d light) {
  728.     float intense;
  729.  
  730.     intense = light.x * snorm [segment][pos][0] + 
  731.               light.y * snorm [segment][pos][1] +
  732.               light.z * snorm [segment][pos][2];
  733.  
  734.     if (intense < 0)
  735.         intense = 0.0;
  736.  
  737.     return (intense);
  738. }
  739.  
  740. GLfloat sphereintense (int segment, int pos, int ysign, vec3d light) {
  741.     float intense;
  742.  
  743.     intense = light.x * sphere [segment][pos][0] + 
  744.               light.y * sphere [segment][pos][1] * (float)ysign +
  745.               light.z * sphere [segment][pos][2];
  746.     
  747.     if (intense < 0)
  748.         intense = 0.0;
  749.  
  750.     return (intense);
  751. }
  752.  
  753. GLfloat capintense (vec3d light) {
  754.     float intense = light.y;
  755.     if (intense < 0)
  756.         intense = 0.0;
  757.     return (intense);
  758. }
  759.  
  760. GLvoid drawtorus (int a, int s, vec3d light) {
  761.     int i, j;
  762.     for (i = 0; i < spts; i++) {
  763.         glBegin (GL_QUAD_STRIP);
  764.         limbcolor (a, s, 0, surfintense (i, 0, light));
  765.         glVertex3f (toroid [i][0][0], toroid [i][0][1], toroid [i][0][2]);
  766.         limbcolor (a, s, 1, surfintense (i + 1, 0, light));
  767.         glVertex3f (toroid [i + 1][0][0], toroid [i + 1][0][1], toroid [i + 1][0][2]);
  768.         for (j = 1; j < qpr; j++) {
  769.             limbcolor (a, s, 0, surfintense (i, j, light));
  770.             glVertex3f (toroid [i][j][0], toroid [i][j][1], toroid [i][j][2]);
  771.             limbcolor (a, s, 1, surfintense (i + 1, j, light));
  772.             glVertex3f (toroid [i + 1][j][0], toroid [i + 1][j][1], toroid [i + 1][j][2]);
  773.         }
  774.         limbcolor (a, s, 0, surfintense (i, 0, light));
  775.         glVertex3f (toroid [i][0][0], toroid [i][0][1], toroid [i][0][2]);
  776.         limbcolor (a, s, 1, surfintense (i + 1, 0, light));
  777.         glVertex3f (toroid [i + 1][0][0], toroid [i + 1][0][1], toroid [i + 1][0][2]);
  778.         glEnd ();
  779.     }
  780. }
  781.  
  782. GLvoid drawSphere (int a, int s, vec3d light, int mode) {
  783.     int i, j;
  784.  
  785.     for (i = 0; i < (spts - 1); i++) {
  786.         glBegin (GL_QUAD_STRIP);
  787.         limbcolor (a, s, 0, sphereintense (i, 0, 1, light));
  788.         glVertex3f (sphere [i][0][0], sphere [i][0][1], sphere [i][0][2]);
  789.         limbcolor (a, s, 1, sphereintense (i + 1, 0, 1, light));
  790.         glVertex3f (sphere [i + 1][0][0], sphere [i + 1][0][1], sphere [i + 1][0][2]);
  791.         for (j = 1; j < qpr; j++) {
  792.             limbcolor (a, s, 0, sphereintense (i, j, 1, light));
  793.             glVertex3f (sphere [i][j][0], sphere [i][j][1], sphere [i][j][2]);
  794.             limbcolor (a, s, 1, sphereintense (i + 1, j, 1, light));
  795.             glVertex3f (sphere [i + 1][j][0], sphere [i + 1][j][1], sphere [i + 1][j][2]);
  796.         }
  797.         limbcolor (a, s, 0, sphereintense (i, 0, 1, light));
  798.         glVertex3f (sphere [i][0][0], sphere [i][0][1], sphere [i][0][2]);
  799.         limbcolor (a, s, 1, sphereintense (i + 1, 0, 1, light));
  800.         glVertex3f (sphere [i + 1][0][0], sphere [i + 1][0][1], sphere [i + 1][0][2]);
  801.         glEnd();
  802.     }
  803.     glBegin (GL_TRIANGLE_FAN);
  804.     limbcolor (a, s, 1, sphereintense (spts, 0, 1, light));
  805.     glVertex3f (0.0, 1.0, 0.0);
  806.     for (j = 0; j < qpr; j++) {
  807.         limbcolor (a, s, 0, sphereintense ((spts - 1), j, 1, light));
  808.         glVertex3f (sphere [(spts - 1)][j][0], sphere [(spts - 1)][j][1], sphere [(spts - 1)][j][2]);
  809.     }
  810.     limbcolor (a, s, 0, sphereintense ((spts - 1), 0, 1, light));
  811.     glVertex3f (sphere [(spts - 1)][0][0], sphere [(spts - 1)][0][1], sphere [(spts - 1)][0][2]);
  812.     glEnd ();
  813.     if (mode == 1)
  814.         return;
  815.     for (i = 0; i < (spts - 1); i++) {
  816.         glBegin (GL_QUAD_STRIP);
  817.         limbcolor (a, s, 0, sphereintense (i, 0, -1, light));
  818.         glVertex3f (sphere [i][0][0], -sphere [i][0][1], sphere [i][0][2]);
  819.         limbcolor (a, s, 1, sphereintense (i + 1, 0, -1, light));
  820.         glVertex3f (sphere [i + 1][0][0], -sphere [i + 1][0][1], sphere [i + 1][0][2]);
  821.         for (j = 1; j < qpr; j++) {
  822.             limbcolor (a, s, 0, sphereintense (i, j, -1, light));
  823.             glVertex3f (sphere [i][j][0], -sphere [i][j][1], sphere [i][j][2]);
  824.             limbcolor (a, s, 1, sphereintense (i + 1, j, -1, light));
  825.             glVertex3f (sphere [i + 1][j][0], -sphere [i + 1][j][1], sphere [i + 1][j][2]);
  826.         }
  827.         limbcolor (a, s, 0, sphereintense (i, 0, -1, light));
  828.         glVertex3f (sphere [i][0][0], -sphere [i][0][1], sphere [i][0][2]);
  829.         limbcolor (a, s, 1, sphereintense (i + 1, 0, -1, light));
  830.         glVertex3f (sphere [i + 1][0][0], -sphere [i + 1][0][1], sphere [i + 1][0][2]);
  831.         glEnd();
  832.     }    
  833.     glBegin (GL_TRIANGLE_FAN);
  834.     limbcolor (a, s, 1, sphereintense (spts, 0, -1, light));
  835.     glVertex3f (0.0, -1.0, 0.0);
  836.     for (j = 0; j < qpr; j++) {
  837.         limbcolor (a, s, 0, sphereintense ((spts - 1), j, -1, light));
  838.         glVertex3f (sphere [(spts - 1)][j][0], -sphere [(spts - 1)][j][1], sphere [(spts - 1)][j][2]);
  839.     }
  840.     limbcolor (a, s, 0, sphereintense ((spts - 1), 0, -1, light));
  841.     glVertex3f (sphere [(spts - 1)][0][0], -sphere [(spts - 1)][0][1], sphere [(spts - 1)][0][2]);
  842.     glEnd ();
  843. }
  844.  
  845. GLvoid drawCap (int a, int s, vec3d light) {
  846.     int j;
  847.     glBegin (GL_TRIANGLE_FAN);
  848.     limbcolor (a, s, 1, capintense(light));
  849.     glVertex3f (0.0, 0.0, 0.0);
  850.     limbcolor (a, s, 0, capintense (light));
  851.     for (j = 0; j < qpr; j++)
  852.         glVertex3f (sphere [0][j][0], sphere [0][j][1], sphere [0][j][2]);
  853.     glVertex3f (sphere [0][0][0], sphere [0][0][1], sphere [0][0][2]);
  854.     glEnd ();
  855. }
  856.  
  857. GLvoid mrecurseLinks (int i, GLfloat pitch, int r, int f, int s, int a, vec3d light) {
  858.  
  859.     vec3d tranlight;
  860.     vec3d atranlight;
  861.     
  862.     tranlight.x = light.x;
  863.     tranlight.y = light.y;
  864.     tranlight.z = light.z;
  865.  
  866.     if (f == 0) {
  867.         glTranslatef (-majrad, 0.0f, majrad);
  868.         glRotatef (-90.0, 0.0f, 1.0f, 0.0f);
  869.         tranlight = vecrotate (tranlight, -90, 0, 1, 0);
  870.     }
  871.  
  872.  
  873.     glPushMatrix ();
  874.     
  875.     glRotatef (pitch + (GLfloat)r, 0.0f, 0.0f, 1.0f);
  876.     tranlight = vecrotate (tranlight, pitch + r, 0, 0, 1);
  877.  
  878.     if (i == s) {
  879.         atranlight.x = tranlight.x;
  880.         atranlight.y = tranlight.y;
  881.         atranlight.z = tranlight.z;
  882.     }
  883.  
  884.     switch (jointstyle) {
  885.     case 1:    drawAxes ();
  886.             break;
  887.     case 2: if (f == 1)
  888.                 break;
  889.             if (i == 0)
  890.                 break;
  891.             glPushMatrix ();
  892.             glScalef (lard * 2.0, lard * 2.0, lard * 2.0);
  893.             glRotatef (90, 1, 0, 0);
  894.             tranlight = vecrotate (tranlight, 90, 1, 0, 0);
  895.             drawSphere (a, i, tranlight, 0);
  896.             glPopMatrix ();
  897.             tranlight = vecrotate (tranlight, -90, 1, 0, 0);
  898.             break;
  899.     }
  900.  
  901.     if (i == 0) {
  902.         switch (capstyle) {
  903.         case 0:
  904.             glRotatef (pitch * 10.0f + (GLfloat)r, 0.0f, 0.0f, 1.0f);
  905.             drawTetra (1.0);
  906.             break;
  907.         case 1:
  908.             glScalef (lard, lard, lard);
  909.             glRotatef (90, 1, 0, 0);
  910.             tranlight = vecrotate (tranlight, 90, 1, 0, 0);
  911.             drawSphere (a, 1, tranlight, 1);
  912.             break;
  913.         case 2:
  914.             glScalef (lard, lard, lard);
  915.             glRotatef (90, 1, 0, 0);
  916.             tranlight = vecrotate (tranlight, 90, 1, 0, 0);
  917.             drawCap (a, 1, tranlight);
  918.             break;
  919.         }
  920.         glPopMatrix ();
  921.         return;
  922.     }
  923.  
  924.     drawtorus (a, i, tranlight);
  925.  
  926.     tranlight = vecrotate (tranlight, 90, 1, 0, 0);
  927.  
  928.     i--;
  929.  
  930.     mrecurseLinks (i, -pitch, r * 2, 0, s, a, tranlight);
  931.  
  932.     if (i == s) {
  933. //        tranlight = vecrotate (tranlight, 90, 1, 0, 0);
  934. //        atranlight = vecrotate (atranlight, 90, 0, 0, 1);
  935. //        glPushMatrix ();
  936.         glRotatef (180.0f, 0.0f, 0.0f, 1.0f);
  937.         drawtorus (a + 5, i, atranlight);
  938.         mrecurseLinks (i - 1, -pitch, r * 2, 0, -1, a + 5, atranlight);
  939. //        glPopMatrix ();
  940.     }
  941.  
  942.     glPopMatrix ();
  943. }
  944.  
  945. GLvoid drawSpinCenter (float pitch) {
  946.     glEnable (GL_BLEND);
  947.  
  948.     glRotatef (pitch * 5, 0.0f, 0.0f, 1.0f);
  949.     glRotatef (-pitch * 5, 0.0f, 1.0f, 0.0f);
  950.     glRotatef (pitch * 5, 1.0f, 0.0f, 0.0f);
  951.  
  952.     glScalef (2.0, 2.0, 2.0);
  953.     drawTetra (0.7);
  954.  
  955.     glRotatef (pitch * 2, 0.0f, 0.0f, 1.0f);
  956.     glRotatef (-pitch * 5, 1.0f, 0.0f, 0.0f);
  957.  
  958.     glScalef (1.5, 1.5, 1.5);
  959.     drawTetra (0.5);
  960.  
  961.     glDisable (GL_BLEND);
  962. }
  963.  
  964. GLvoid drawPulseBlob (float pitch, vec3d light) {
  965.     float sfa = 0.3 * sin (pitch / 40) + 1.2;
  966.     float sfb = 0.4 * cos (pitch / 44 + 1) + 1.2;
  967.     glPushMatrix ();
  968.     glRotatef (-45, 0.0, 0.0, 1.0);
  969.     glRotatef (45, 1.0, 0.0, 0.0);
  970.     light = vecrotate (light, -45, 0, 0, 1);
  971.     light = vecrotate (light, 45, 1, 0, 0);
  972.     glScalef (sfa, sfb, sfa);
  973.     drawSphere (8, 1, light, 0);
  974.     glPopMatrix ();
  975. }
  976.  
  977. GLvoid drawScene(GLvoid)
  978. {
  979.     static float pitch = 0.0;
  980.     int i;
  981.  
  982.     vec3d lightsource;
  983.     
  984.     lightsource.x = masterlight.x;
  985.     lightsource.y = masterlight.y;
  986.     lightsource.z = masterlight.z;
  987.  
  988.     if (bufstyle)
  989.         glClear(GL_DEPTH_BUFFER_BIT);
  990.     else
  991.         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  992.  
  993.     glPushMatrix ();  // master view
  994.  
  995.     glTranslatef (0.5 * sin (pitch / 20), 0.0, -20.0f + 3.0 * cos (pitch/20));
  996.  
  997.     for (i = 0; i < noodlecount; i++)
  998.         mrecurseLinks (armlengths [i], rspeeds [i] * pitch + i * 200, 
  999.                        i * 8 + 10, 1, -1, i, lightsource);
  1000.  
  1001.     switch (centerstyle) {
  1002.     case 0:    drawSpinCenter (pitch);
  1003.             break;
  1004.     case 1: drawPulseBlob (pitch, masterlight);
  1005.             break;
  1006.     }
  1007.  
  1008.     glPopMatrix ();   // pop master view
  1009.  
  1010.     glFinish();
  1011.  
  1012.     SwapBuffers(ghDC);
  1013.  
  1014.     framecount++;
  1015.  
  1016.     pitch += PITCH_SPEED;
  1017.     if (pitch > 10000000.0) {
  1018.         pitch -= 10000000.0;
  1019.     }
  1020.     if (pitch < 0) {
  1021.         pitch += 10000000.0;
  1022.     }
  1023.  
  1024.     if (colorcycle) {
  1025.         cycleaccum++;
  1026.         cyclepitch += cyclespeed;
  1027.         if (cycleaccum == 10) {
  1028.             cycleaccum = 0;
  1029.             cyclecolors (cyclepitch);
  1030.         }
  1031.     }
  1032. }
  1033.